package com.yunquan.ohana.ui.calendar.task.add

import android.app.Application
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.os.Bundle
import androidx.databinding.ObservableArrayList
import androidx.databinding.ObservableField
import androidx.lifecycle.LifecycleOwner
import com.google.gson.Gson
import com.yunquan.ohana.BR
import com.yunquan.ohana.R
import com.yunquan.ohana.base.binding.command.BindingAction
import com.yunquan.ohana.base.binding.command.BindingCommand
import com.yunquan.ohana.base.binding.command.BindingConsumer
import com.yunquan.ohana.base.bus.event.SingleLiveEvent
import com.yunquan.ohana.base.ui.AppManager
import com.yunquan.ohana.base.ui.BaseViewModel
import com.yunquan.ohana.entity.RoleEntity
import com.yunquan.ohana.entity.TaskEntity
import com.yunquan.ohana.entity.TaskEntityVo
import com.yunquan.ohana.entity.TasksToRoleVo
import com.yunquan.ohana.http.BaseHttp
import com.yunquan.ohana.http.observer.BaseObserver
import com.yunquan.ohana.http.transformer.CommonTransformer
import com.yunquan.ohana.ui.calendar.event.add.AddEventRoleItemViewModel
import com.yunquan.ohana.ui.calendar.event.week.dialog.BottomDeleteDialog
import com.yunquan.ohana.ui.calendar.profiles.add.AddProfilesActivity
import com.yunquan.ohana.utils.DateTimeHelper
import com.yunquan.ohana.utils.DateUtils
import com.yunquan.ohana.utils.L
import com.yunquan.ohana.utils.LocaleHelper
import com.yunquan.ohana.utils.StringUtils
import com.yunquan.ohana.utils.ToastUtils
import com.yunquan.ohana.utils.Utils
import io.reactivex.rxjava3.disposables.Disposable
import me.tatarka.bindingcollectionadapter2.ItemBinding
import okhttp3.RequestBody.Companion.toRequestBody
import java.time.LocalDate
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneId
import java.time.format.DateTimeFormatter
import java.util.Locale

class TaskAddViewModel(application: Application) : BaseViewModel(application) {

    val ui = SingleLiveEvent<Int>()

    val title = ObservableField<String>()
    val taskTitle = ObservableField<String>()
    val taskEmoji = ObservableField<String>()
    val taskDate = ObservableField<String>()
    val taskTime = ObservableField<String>()
    val isRepeats = ObservableField<Boolean>()

    val everyCount = ObservableField("1")
    val everyTypeIndex = ObservableField(0)
    val repeatsUntil = ObservableField<String>()
    val isRepeatUntil = ObservableField(false)

    val everyWeekSun = ObservableField(false)
    val everyWeekMon = ObservableField(false)
    val everyWeekTue = ObservableField(false)
    val everyWeekWen = ObservableField(false)
    val everyWeekThu = ObservableField(false)
    val everyWeekFri = ObservableField(false)
    val everyWeekSat = ObservableField(false)

    val isUserType = ObservableField(false)
    val isShowDelete = ObservableField(false)
    val roleItems = ObservableArrayList<AddEventRoleItemViewModel<TaskAddViewModel>>()
    val roleItemBinding = ItemBinding.of<AddEventRoleItemViewModel<TaskAddViewModel>>(
        BR.addEventRoleItemViewModel,
        R.layout.item_add_edit_task_role,
    )

    var mDeviceId: String? = null
    var mRoleId: String? = null
    var mTaskEntity: TaskEntity? = null
    var mTaskDate: LocalDate? = null
    var mTaskTime: LocalTime? = null
    var mRepeatsUntilDate: LocalDate? = null

    val mDateFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("EEE, MMM d")
    val mTimeFormat: DateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm")

    val onTaskDateChange = BindingCommand(object : BindingConsumer<Boolean> {
        override fun call(t: Boolean) {
            if (t) {
                taskDate.set(Utils.instance.getString(R.string.select_date))
                mTaskDate = null
                changeTaskDate()
            }
        }
    })
    val onTaskDateClick = BindingCommand<Any>(object : BindingAction {
        override fun call() {
            changeTaskDate()
        }
    })
    val onTaskTimeChange = BindingCommand(object : BindingConsumer<Boolean> {
        override fun call(t: Boolean) {
            if (t) {
                taskTime.set(Utils.instance.getString(R.string.select_date))
                mTaskTime = null
                changeTaskTime()
            }
        }
    })
    val onTaskTimeClick = BindingCommand<Any>(object : BindingAction {
        override fun call() {
            changeTaskTime()
        }
    })
    val onRepeatsUntilDateChange = BindingCommand(object : BindingConsumer<Boolean> {
        override fun call(t: Boolean) {
            isRepeatUntil.set(t)
            if (t) {
                repeatsUntil.set(Utils.instance.getString(R.string.select_date))
                mRepeatsUntilDate = null
                changeRepeatsUntilDate()
            }
        }
    })
    val onRepeatsUntilDateClick = BindingCommand<Any>(object : BindingAction {
        override fun call() {
            changeRepeatsUntilDate()
        }
    })

    val onEveryGroupClick = BindingCommand(object : BindingConsumer<Int> {
        override fun call(t: Int) {
            everyTypeIndex.set(
                when (t) {
                    R.id.rb_day -> {
                        everyWeekSun.set(false)
                        everyWeekMon.set(false)
                        everyWeekTue.set(false)
                        everyWeekWen.set(false)
                        everyWeekThu.set(false)
                        everyWeekFri.set(false)
                        everyWeekSat.set(false)
                        1
                    }

                    R.id.rb_week -> {
                        2
                    }

                    R.id.rb_month -> {
                        everyWeekSun.set(false)
                        everyWeekMon.set(false)
                        everyWeekTue.set(false)
                        everyWeekWen.set(false)
                        everyWeekThu.set(false)
                        everyWeekFri.set(false)
                        everyWeekSat.set(false)
                        3
                    }

                    R.id.rb_year -> {
                        everyWeekSun.set(false)
                        everyWeekMon.set(false)
                        everyWeekTue.set(false)
                        everyWeekWen.set(false)
                        everyWeekThu.set(false)
                        everyWeekFri.set(false)
                        everyWeekSat.set(false)
                        4
                    }

                    else -> {
                        everyWeekSun.set(false)
                        everyWeekMon.set(false)
                        everyWeekTue.set(false)
                        everyWeekWen.set(false)
                        everyWeekThu.set(false)
                        everyWeekFri.set(false)
                        everyWeekSat.set(false)
                        0
                    }
                }
            )
        }
    })

    val onAddProfilesClick = BindingCommand<Any>(object : BindingAction {
        override fun call() {
            val bundle = Bundle()
            bundle.putString("deviceId", mDeviceId)
            bundle.putBoolean("userType", isUserType.get() ?: false)
            startActivityResult(AddProfilesActivity::class.java, bundle)
        }
    })

    val onAddClick = BindingCommand<Any>(object : BindingAction {
        override fun call() {
            if (mTaskEntity == null) {
                pushAddTask()
            } else {
                pushEditTask()
            }
        }
    })

    val onDeleteClick = BindingCommand<Any>(object : BindingAction {
        override fun call() {
            val deleteDialog = BottomDeleteDialog(AppManager.appManager.currentActivity()!!)
            deleteDialog.setTitle(Utils.instance.getString(R.string.delete))
            deleteDialog.setTip(Utils.instance.getString(R.string.task_delete_tip))
            deleteDialog.setOnDeleteClick { _ ->
                deleteEvent()
            }
            deleteDialog.show()
        }
    })

    override fun onCreate(owner: LifecycleOwner) {
        super.onCreate(owner)
        title.set(Utils.instance.context.getString(R.string.add_task))
    }

    private fun changeTaskDate() {
        DateTimeHelper.showDatePicker(mTaskDate) { temp ->
            mTaskDate = temp
            taskDate.set(mTaskDate!!.format(mDateFormat))
            everyWeekSun.set(false)
            everyWeekMon.set(false)
            everyWeekTue.set(false)
            everyWeekWen.set(false)
            everyWeekThu.set(false)
            everyWeekFri.set(false)
            everyWeekSat.set(false)
            when (temp.dayOfWeek.value) {
                7 -> everyWeekSun.set(true)
                1 -> everyWeekMon.set(true)
                2 -> everyWeekTue.set(true)
                3 -> everyWeekWen.set(true)
                4 -> everyWeekThu.set(true)
                5 -> everyWeekFri.set(true)
                6 -> everyWeekSat.set(true)
            }
        }
    }

    private fun changeTaskTime() {
        if (mTaskDate == null) {
            ToastUtils.showShort(R.string.error_start_date_tip)
            return
        }
        DateTimeHelper.showTimePicker(mTaskTime) { temp ->
            mTaskTime = temp
            taskTime.set(mTaskTime!!.format(mTimeFormat))
        }
    }

    private fun changeRepeatsUntilDate() {
        DateTimeHelper.showDatePicker(mRepeatsUntilDate) { temp ->
            mRepeatsUntilDate = temp
            repeatsUntil.set(mRepeatsUntilDate!!.format(mDateFormat))
        }
    }

    fun getProfilesList() {
        val map = mutableMapOf<String, Any>()
        map["deviceId"] = mDeviceId!!
        val body = Gson().toJson(map).toRequestBody(BaseHttp.MEDIA_TYPE_JSON)
        BaseHttp.api.getDeviceRoleListById(body)
            .compose(CommonTransformer())
            .subscribe(object : BaseObserver<List<RoleEntity>>() {
                override fun onSubscribe(d: Disposable) {
                    super.onSubscribe(d)
                    showLoading()
                }

                override fun onSuccess(result: List<RoleEntity>?) {
                    super.onSuccess(result)
                    roleItems.clear()
                    val roleIdList = mTaskEntity?.tasksToRoleVos?.map { it.roleId } ?: emptyList()
                    result?.forEach {
                        roleItems.add(
                            AddEventRoleItemViewModel(
                                this@TaskAddViewModel,
                                it,
                                checked = roleIdList.contains(it.id)
                            )
                        )
                    }
                }

                override fun onComplete() {
                    super.onComplete()
                    hideLoading()
                }
            })
    }

    private fun pushEditTask() {
        if (StringUtils.isEmpty(taskTitle.get())) {
            ToastUtils.showShort(R.string.error_task_title_tip)
            return
        }
        val roleList = roleItems.filter { it.checked.get() == true }.map { it.data!! }.toList()
        if (!roleList.isNotEmpty()) {
            ToastUtils.showShort(R.string.error_role_tip)
            return
        }
        if (mTaskDate == null) {
            ToastUtils.showShort(R.string.error_start_time_tip)
            return
        }
        var startDateTime: LocalDateTime
        var reminderTime: LocalDateTime?
        if (mTaskTime == null) {
            val notTime = LocalTime.of(0, 0, 0)
            startDateTime = LocalDateTime.of(mTaskDate!!, notTime)
            reminderTime = null
        } else {
            startDateTime = LocalDateTime.of(mTaskDate!!, mTaskTime!!)
            reminderTime = startDateTime
        }
        val mRepeatsUntilDateTime = if (mRepeatsUntilDate != null) {
            LocalDateTime.of(mRepeatsUntilDate, LocalTime.of(0, 0, 0))
        } else {
            null
        }

        var isRepeat: Int = 0
        var repeatRule: String? = null
        if (isRepeats.get() == true) {
            when (everyTypeIndex.get()) {
                0 -> {
                    isRepeat = 1
                    repeatRule = everyCount.get().toString()
                }

                1 -> {
                    isRepeat = 2
                }

                2 -> {
                    isRepeat = 3
                    val sb = StringBuilder()
                    if (everyWeekSun.get() == true) {
                        sb.append("1").append(",")
                    }
                    if (everyWeekMon.get() == true) {
                        sb.append("2").append(",")
                    }
                    if (everyWeekTue.get() == true) {
                        sb.append("3").append(",")
                    }
                    if (everyWeekWen.get() == true) {
                        sb.append("4").append(",")
                    }
                    if (everyWeekThu.get() == true) {
                        sb.append("5").append(",")
                    }
                    if (everyWeekFri.get() == true) {
                        sb.append("6").append(",")
                    }
                    if (everyWeekSat.get() == true) {
                        sb.append("7").append(",")
                    }
                    if (sb.isNotEmpty()) {
                        repeatRule = sb.substring(0, sb.length - 1)
                    } else {
                        ToastUtils.showShort(R.string.please_select_at_least_one_repetition_time)
                        return
                    }
                }

                3 -> {
                    isRepeat = 4
                    startDateTime.atZone(ZoneId.systemDefault()).toEpochSecond()
                }

                4 -> {
                    isRepeat = 5
                    startDateTime.atZone(ZoneId.systemDefault()).toEpochSecond()
                }
            }
        }
        val bean = TaskEntityVo(
            id = mTaskEntity?.id,
            deviceId = mDeviceId,
            title = taskTitle.get(),
            emoji = taskEmoji.get(),
            isRepeat = isRepeat.toString(),
            startDate = startDateTime.atZone(ZoneId.systemDefault()).toEpochSecond().toString(),
            endDate = mRepeatsUntilDateTime?.atZone(ZoneId.systemDefault())?.toEpochSecond().toString(),
            reminderTime = reminderTime?.atZone(ZoneId.systemDefault())?.toEpochSecond().toString(),
            deviceRoleDtoList = roleList.map { TasksToRoleVo(roleId = it.id) },
            repeatRule = repeatRule,
        )
        val params = Gson().toJson(bean)
        L.i(params)
        val body = params.toRequestBody(BaseHttp.MEDIA_TYPE_JSON)
        BaseHttp.api.updateTasksById(body)
            .compose(CommonTransformer())
            .subscribe(object : BaseObserver<Boolean>() {
                override fun onSubscribe(d: Disposable) {
                    super.onSubscribe(d)
                    showLoading()
                }

                override fun onSuccess(result: Boolean?) {
                    super.onSuccess(result)
                    if (result == true) {
                        ui.value = 0
                    } else {
                        ToastUtils.showShort(Utils.instance.getString(R.string.edit_task_failed))
                    }
                }

                override fun onComplete() {
                    super.onComplete()
                    hideLoading()
                }
            })
    }

    private fun pushAddTask() {
        if (StringUtils.isEmpty(taskTitle.get())) {
            ToastUtils.showShort(R.string.error_task_title_tip)
            return
        }
        val roleList = roleItems.filter { it.checked.get() == true }.map { it.data!! }.toList()
        if (!roleList.isNotEmpty()) {
            ToastUtils.showShort(R.string.error_role_tip)
            return
        }
        if (mTaskDate == null) {
            ToastUtils.showShort(R.string.please_select_the_task_date)
            return
        }
        var startDateTime: LocalDateTime
        var reminderTime: LocalDateTime?
        if (mTaskTime == null) {
            val notTime = LocalTime.of(0, 0, 0)
            startDateTime = LocalDateTime.of(mTaskDate!!, notTime)
            reminderTime = null
        } else {
            startDateTime = LocalDateTime.of(mTaskDate!!, mTaskTime!!)
            reminderTime = startDateTime
        }

        val mRepeatsUntilDateTime = if (mRepeatsUntilDate != null) {
            LocalDateTime.of(mRepeatsUntilDate, LocalTime.of(0, 0, 0))
        } else {
            null
        }

        var isRepeat = 0
        var repeatRule: String? = null
        if (isRepeats.get() == true) {
            when (everyTypeIndex.get()) {
                0 -> {
                    isRepeat = 1
                    repeatRule = everyCount.get().toString()
                }

                1 -> {
                    isRepeat = 2
                }

                2 -> {
                    isRepeat = 3
                    val sb = StringBuilder()
                    if (everyWeekSun.get() == true) {
                        sb.append("1").append(",")
                    }
                    if (everyWeekMon.get() == true) {
                        sb.append("2").append(",")
                    }
                    if (everyWeekTue.get() == true) {
                        sb.append("3").append(",")
                    }
                    if (everyWeekWen.get() == true) {
                        sb.append("4").append(",")
                    }
                    if (everyWeekThu.get() == true) {
                        sb.append("5").append(",")
                    }
                    if (everyWeekFri.get() == true) {
                        sb.append("6").append(",")
                    }
                    if (everyWeekSat.get() == true) {
                        sb.append("7").append(",")
                    }
                    if (sb.isNotEmpty()) {
                        repeatRule = sb.substring(0, sb.length - 1)
                    } else {
                        ToastUtils.showShort(R.string.please_select_at_least_one_repetition_time)
                        return
                    }
                }

                3 -> {
                    isRepeat = 4
                }

                4 -> {
                    isRepeat = 5
                }
            }
        }
        val bean = TaskEntityVo(
            deviceId = mDeviceId,
            title = taskTitle.get(),
            emoji = taskEmoji.get(),
            isRepeat = isRepeat.toString(),
            startDate = startDateTime.atZone(ZoneId.systemDefault()).toEpochSecond().toString(),
            endDate = mRepeatsUntilDateTime?.atZone(ZoneId.systemDefault())?.toEpochSecond().toString(),
            reminderTime = reminderTime?.atZone(ZoneId.systemDefault())?.toEpochSecond().toString(),
            deviceRoleDtoList = roleList.map { TasksToRoleVo(roleId = it.id) },
            repeatRule = repeatRule,
        )
        val params = Gson().toJson(bean)
        L.i(params)
        val body = params.toRequestBody(BaseHttp.MEDIA_TYPE_JSON)
        BaseHttp.api.createTasks(body)
            .compose(CommonTransformer())
            .subscribe(object : BaseObserver<TaskEntity>() {
                override fun onSubscribe(d: Disposable) {
                    super.onSubscribe(d)
                    showLoading()
                }

                override fun onSuccess(result: TaskEntity?) {
                    super.onSuccess(result)
                    if (result != null) {
                        mTaskEntity = result
                        ui.value = 0
                    } else {
                        ToastUtils.showShort(Utils.instance.getString(R.string.failed_to_create_task))
                    }
                }

                override fun onComplete() {
                    super.onComplete()
                    hideLoading()
                }
            })
    }

    private fun deleteEvent() {
        if (mTaskEntity?.id == null) {
            ToastUtils.showShort(R.string.delete_failed)
            return
        }
        val map = mutableMapOf<String, Any>()
        map["deviceId"] = mDeviceId!!
        map["tasksId"] = mTaskEntity?.id!!
        map["roleIds"] = arrayListOf(mRoleId)
        val body = Gson().toJson(map).toRequestBody(BaseHttp.MEDIA_TYPE_JSON)
        BaseHttp.api.deleteTasks(body)
            .compose(CommonTransformer())
            .subscribe(object : BaseObserver<Boolean>() {
                override fun onSubscribe(d: Disposable) {
                    super.onSubscribe(d)
                    showLoading()
                }

                override fun onSuccess(result: Boolean?) {
                    super.onSuccess(result)
                    if (result == true) {
                        ui.value = 0
                    } else {
                        ToastUtils.showShort(Utils.instance.getString(R.string.task_deletion_failed))
                    }
                }

                override fun onComplete() {
                    super.onComplete()
                    hideLoading()
                }
            })
    }
}